package main

import (
	"fmt"
	"reflect"
	"strconv"
)

type person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
	sex  int    `json:"sex"`
}

type T struct {
}

func (T) M1() {

}
func (T) M2() {

}

type S T

type Interface interface {
	Met1()
	Met2()
}

type NewInterface interface {
	Interface
	Met2()
}

type Test struct {
	NewInterface
	Interface
}

func (t Test) Met1() {
}
func (t Test) Met2() {
}

func (p person) String() string {
	return fmt.Sprintf("Name is %s, Age is %d", p.Name, p.Age)
}

func main() {

	/*
		i := 3
		iv := reflect.ValueOf(i)
		it := reflect.TypeOf(i)
		il := iv.Interface().(int)

		fmt.Println(iv, it.String(), il)

		ipv := reflect.ValueOf(&i)

		fmt.Println(ipv.CanSet())
		fmt.Println(iv.CanSet())

		ipv.Elem().SetInt(66)
		ipv.Elem().Interface()

		fmt.Println(i)

		var w io.Writer = os.Stdout
		fmt.Println(reflect.TypeOf(w)) // "*os.File"
	*/

	/* 结构体反射演示
	p := person{Name: "郭峥", Age: 18, sex: 1}
	ppt := reflect.TypeOf(p)
	ppv := reflect.ValueOf(&p)
	ppv.Elem().Field(0).SetString("张三")
	ppv.Elem().FieldByName("Age").SetInt(12) //区分大小写的
	//ppv.Elem().FieldByName("sex").SetInt(10)

	fmt.Println(ppt.FieldByName("sex"))

	fmt.Println(p)

	fmt.Println("获取结构体中某个字段的值：")
	fmt.Println(ppv.Elem().Field(0).Interface().(string))
	*/

	/* 反射获取结构体的字段和方法
	p := person{Name: "郭峥", Age: 18, sex: 1}
	pt := reflect.TypeOf(p)

	for i := 0; i < pt.NumField(); i++ {

		fmt.Println("字段", pt.Field(i).Name)
	}

	for i := 0; i < pt.NumMethod(); i++ {

		fmt.Println("方法", pt.Method(i).Name)
	}
	//获取某一个方法或者字段
	fmt.Println(pt.FieldByName("Age"))
	fmt.Println(pt.MethodByName("String"))

	stringerType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
	writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()
	fmt.Println("是否实现了fmt.Stringer：", pt.Implements(stringerType))
	fmt.Println("是否实现了io.Writer：", pt.Implements(writerType))

	*/

	/*  struct 和 json的相互转换
	p := person{Name: "郭峥", Age: 18, sex: 1}
	jsonB, err := json.Marshal(p)

	if err == nil {
		fmt.Println(string(jsonB))
		//{"Name":"郭峥","Age":18}，私有字段是过滤掉的
	}

	respJSON := "{\"name\":\"李四\",\"age\":40,\"sex\":10}"
	json.Unmarshal([]byte(respJSON), &p)

	fmt.Println(p)
	//Name is 李四, Age is 40   会自动调用String 方法 并且私有字段是过滤掉的

	*/

	/* 反射实现 struct 转 json
	p := person{Name: "郭峥", Age: 18, sex: 1}
	pv := reflect.ValueOf(p)
	pt := reflect.TypeOf(p)
	//自己实现的struct to json
	jsonBuilder := strings.Builder{}
	jsonBuilder.WriteString("{")

	num := pt.NumField()
	for i := 0; i < num; i++ {
		fmt.Println(pt.FieldByName("sex"))
		jsonTag := pt.Field(i).Tag.Get("json")
		jsonBuilder.WriteString("\"" + jsonTag + "\"")
		jsonBuilder.WriteString(":")

		//获取字段的值
		jsonBuilder.WriteString(fmt.Sprintf("\"%v\"", pv.Field(i)))

		if i < num-1 {
			jsonBuilder.WriteString(",")
		}
	}
	jsonBuilder.WriteString("}")
	fmt.Println(jsonBuilder.String())

	*/

	var s S
	var spt *S

	dumpMethodSet(s)
	dumpMethodSet(spt)

}

func Sprint(x interface{}) string {
	type stringer interface {
		String() string
	}
	switch x := x.(type) {
	case stringer:
		return x.String()
	case string:
		return x
	case int:
		return strconv.Itoa(x)
	// ...similar cases for int16, uint32, and so on...
	case bool:
		if x {
			return "true"
		}
		return "false"
	default:
		// array, chan, func, map, pointer, slice, struct
		return "???"
	}
}

func dumpMethodSet(i interface{}) {
	dynTyp := reflect.TypeOf(i)

	if dynTyp == nil {
		fmt.Printf("there is no dynamic type\n")
		return
	}

	n := dynTyp.NumMethod()
	if n == 0 {
		fmt.Printf("%s's method set is empty!\n", dynTyp)
		return
	}

	fmt.Printf("%s's method set:\n", dynTyp)
	for j := 0; j < n; j++ {
		fmt.Println("-", dynTyp.Method(j).Name)
	}
	fmt.Printf("\n")
}
